/*
 * BSM6.0
 *
 * Copyright 2012-2013 (C) SINODATA CO., LTD. All Rights Reserved.
 */
package com.sinodata.bsm.cicp.task;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.jms.JMSException;

import org.apache.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import bsh.EvalError;
import bsh.Interpreter;

import com.sinodata.bsm.cicp.cache.CacheFactory;
import com.sinodata.bsm.cicp.cache.PropertyCache;
import com.sinodata.bsm.cicp.cache.ResAttrValCache;
import com.sinodata.bsm.cicp.cache.ResCache;
import com.sinodata.bsm.cicp.cache.ResRelationCache;
import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.message.Messenger;
import com.sinodata.bsm.common.vo.Property;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResAttrVal;
import com.sinodata.bsm.common.vo.ResPropertyValue;
import com.sinodata.bsm.common.vo.ResPropertyValue.PropValue;

/**
 * <p>
 * Description: 
 * </p>
 *
 * @author tangli
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-19 上午11:09:17          tangli         1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */
public class CollectJob implements Job {
    protected final static String JOB_KEY_RESID = "JOB_KEY_RESID";
    protected final static String JOB_KEY_TASKID = "JOB_KEY_TASKID";
    private final ResCache resCache = (ResCache) CacheFactory.getCache(ResCache.class);
    private final PropertyCache propertyCache = (PropertyCache) CacheFactory.getCache(PropertyCache.class);
    private final ResAttrValCache resAttrVal = (ResAttrValCache) CacheFactory.getCache(ResAttrValCache.class);
    private final ResRelationCache resRelationCache = (ResRelationCache) CacheFactory.getCache(ResRelationCache.class);

    private final Interpreter interpreter = new Interpreter();
    private static final String REGEX_OPERATOR = ".*[\\+\\-\\*\\/].*";

    private static Logger logger = Logger.getLogger(CollectJob.class);

    /**
     * 
     */
    public CollectJob() {
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            JobDataMap dataMap = context.getJobDetail().getJobDataMap();
            dataMap.put("begin", System.currentTimeMillis());
            Long resId = dataMap.getLong(JOB_KEY_RESID);
            Long taskId = dataMap.getLong(JOB_KEY_TASKID);
            Boolean temporary = dataMap.getBoolean("IS_TEMPORARY");

            Res res = resCache.get(resId);
            if (res == null || res.getPaused() == 1) {
                return;
            }

            Collector collector = CollectorFactory.getCollector(resId, taskId);
            Date collectDate = new Date();
            try {
                Date pfTime = context.getPreviousFireTime();
                if (pfTime == null) {
                    collector.setInterval(0);
                } else {
                    collector.setInterval((System.currentTimeMillis() - pfTime.getTime()) / 2);
                }
                List<ResPropertyValue> values = collector.collect(res.getIp());
                Map<Long, String> propMap = collector.getPropMap();
                if (propMap == null) {//logger.warn("未找到采集器指标映射关系:资源编号[" + resId + "],采集器编号[" + ciId + "]");
                    return;
                }
                if (values == null) {
                    return;
                }
                List<Long> childrenResIdList = resRelationCache.getChildrenByResId(resId);
                Map<String, Res> childrenResMap = new HashMap<String, Res>();
                if (childrenResIdList != null && childrenResIdList.size() > 0) {
                    for (Long childrenResId : childrenResIdList) {
                        Res childrenRes = resCache.get(childrenResId);
                        childrenResMap.put(childrenRes.getInternalId(), childrenRes);
                    }
                }
                for (ResPropertyValue valuex : values) {
                    valuex.setTemporary(temporary);
                    if (valuex.getTime() == null) {
                        valuex.setTime(collectDate);
                    }
                    /**
                     * 批量采集到的数据在这里处理
                     * ***************begin******************
                     */
                    String inid = valuex.getInid();
                    if (inid != null && childrenResMap.get(inid) != null) {//批量采集的情况
                        valuex.setResId(childrenResMap.get(inid).getId());
                    } else {//单资源采集
                        valuex.setResId(resId);
                    }
                    /**
                     * ***************end********************
                     */
                    valuex.setTaskId(taskId);
                    PropValue[] propValues = valuex.getValues();
                    Map<String, String> collectValues = new HashMap<String, String>();
                    for (PropValue propValue : propValues) {
                        if (propValue != null) {
                            collectValues.put(propValue.field, propValue.value);
                        }
                    }
                    List<PropValue> propValueList = new ArrayList<PropValue>();
                    for (Long propId : propMap.keySet()) {
                        Property property = propertyCache.get(propId);
                        if (property == null) {
                            continue;
                        }
                        String fieldExp = propMap.get(propId);
                        String fieldValue = null;
                        Long propdatatype = property.getDataTypeId();
                        if (propdatatype != 1L && propdatatype != 9L) {
                            fieldValue = calculatePropValue(fieldExp, collectValues, resId);
                        }

                        fieldValue = fieldValue == null ? collectValues.get(fieldExp) : fieldValue;
                        if (fieldValue == null) {
                            continue;
                        }
                        fieldValue = format(fieldValue, property.getDataTypeId(), property.getFormat());
                        PropValue propValue = ResPropertyValue.createPropValue(propId, fieldValue, fieldExp);
                        propValueList.add(propValue);
                    }
                    valuex.setValues(propValueList.toArray(new PropValue[propValueList.size()]));
                    sendPropertyValue(valuex);
                }
            } catch (Throwable t) {
                logger.error("Failed to collect property value,resId=" + resId + ",taskId=" + taskId, t);
            }//logger.info("job " + resId + "end.");
        } catch (Throwable e) {
            logger.error("failed to collect property value", e);
        }
    }

    /**
     * 根据指标的字段表达式进行指标值计算
     *
     * @param collectValues
     */
    public String calculatePropValue(String fieldExp, Map<String, String> collectValues, Long resId) {
        boolean isNumber = fieldExp.trim().matches(REGEX_OPERATOR);
        // 1.设置指标变量
        for (String field : collectValues.keySet()) {
            if (fieldExp.contains(field)) {
                String valStr = collectValues.get(field);
                if (valStr != null) {
                    try {
                        if (isNumber) {
                            try {
                                this.interpreter.set(field, Double.parseDouble(valStr));
                            } catch (Exception e) {
                            }
                        } else {
                            this.interpreter.set(field, valStr);
                        }
                    } catch (Exception e) {
                    }
                }
            }
        }
        // 2.替换属性变量
        fieldExp = replaceAttributeValue(fieldExp, resId);
        // 3.进行计算
        try {
            Object o = this.interpreter.eval(fieldExp);
            return o != null ? o.toString() : "";
        } catch (EvalError e) {
            logger.error("failed to calc property:" + fieldExp, e);
            return "";
        }
    }

    /**
     * 发送实时指标值到center的队列中。
     */
    private void sendPropertyValue(ResPropertyValue valuex) {
        logger.info(valuex);
        try {
            Messenger.getInstance().sendPropertyValue(valuex);
        } catch (JMSException e) {
            logger.error("failed to send property value:" + valuex, e);
        }
    }

    private String replaceAttributeValue(String str, Long resId) {
        if (str == null || str.length() == 0) {
            return str;
        }
        Pattern pattern = Pattern.compile("\\$\\{(\\d+)\\}");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            Long attrId = Long.parseLong(matcher.group(1).trim());
            String attrVal = getAttributeValue(resId, attrId);
            if (attrVal != null) {
                str = str.replaceAll("\\$\\{" + attrId + "\\}", attrVal);
            }
        }
        return str;
    }

    private String getAttributeValue(Long resId, Long attrId) {
        ResAttrVal attrVal = resAttrVal.get(resId, attrId);
        if (attrVal != null) {
            return attrVal.getAttrValue();
        }
        return null;
    }

    private String format(String value, Long dataType, String format) {
        if (format == null || format.length() == 0) {
            return value;
        }
        //日期型指标值，如果值的形式为:20100511155730，则转换为毫秒数
        //        if (dataType == 3) {
        //            if (value.length() == 14) {
        //                value = "" + (new SimpleDateFormat("yyyyMMddHHmmss").parse(value).getTime());
        //            }
        //        }
        try {
            if (dataType == 2L) {
                if (value.trim().length() == 0) {
                    logger.debug("数字类型，value=‘’则返回0");
                    return "0";
                }
                Double dv = Double.parseDouble(value);
                DecimalFormat df = new DecimalFormat(format);
                value = df.format(dv);
            }
        } catch (Exception e) {
            logger.error("数据格式化失败[" + value + "]", e);
        } finally {
            return value;
        }
    }
}
